package ru.susu.algebra.partition.polyhedron;

import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ru.susu.algebra.io.FileUtilities;
import ru.susu.algebra.partition.Partition;
import ru.susu.algebra.partition.PartitionsIterator;
import ru.susu.algebra.partition.polyhedron.checkers.IVertexChecker;
import ru.susu.algebra.partition.polyhedron.checkers.PowVertexChecker;
import ru.susu.algebra.partition.polyhedron.checkers.ProductVertexChecker;
import ru.susu.algebra.partition.polyhedron.checkers.SimplexMethodVertexChecker;
import ru.susu.algebra.partition.polyhedron.checkers.TwoCompositionChecker;
import ru.susu.algebra.properties.MapPropertySource;

/**
 * @author akargapolov
 * @since: 04.04.2010
 */
public class PartitionDistributionExecutor
{
	private static final int NUMBER = 100;
	public static final String FILENAME_PREFIX = "resources/distribution/";
	private static final IVertexChecker[] CHECKERS =
	{ new PowVertexChecker(), new ProductVertexChecker(), new TwoCompositionChecker(), new SimplexMethodVertexChecker() };

	public static void main(String[] args)
	{
		new PartitionDistributor().run();
	}

	public static class PartitionDistributor implements Runnable
	{
		private Map<String, PrintStream> _name2Files = new HashMap<String, PrintStream>();
		private VertexesFinder _vertexesContainer;

		@Override
		public void run()
		{
			createVertexesContainer();
			for (int number = 1;number <= NUMBER; number++)
			{
				processOneNumber(number);
			}
		}

		private void processOneNumber(int number)
		{
			Date start = new Date();

			FileUtilities.makeDirectory(FILENAME_PREFIX + number);

			List<Partition> vertexes = new ArrayList<Partition>(_vertexesContainer.getVertexes(number));
			PartitionsIterator partitions = new PartitionsIterator(number);
			while (partitions.hasNext())
			{
				Partition partition = partitions.next();
				for (IVertexChecker  checker : CHECKERS)
				{
					String check = checker.check(partition, vertexes);
					if (IVertexChecker.CHECKED_RESULT.equals(check))
					{
						continue;
					}
					processCheckResult(checker, check, number);
					break;
				}
			}

			closeFiles();
			printVertexes(number);

			System.out.println("Save distribution for " + number + "  time: " + (new Date().getTime() - start.getTime()) + "ms");
		}

		private void closeFiles()
		{
			for (PrintStream ps : _name2Files.values())
			{
				ps.close();
			}
			_name2Files = new HashMap<String, PrintStream>();
		}

		private void printVertexes(int number)
		{
			try
			{
				FileOutputStream stream = new FileOutputStream(FILENAME_PREFIX + number +  "/Vertexes.txt");
				BufferedOutputStream buffered = new BufferedOutputStream(stream);
				PrintStream printStream = new PrintStream(buffered);
				for (Partition p : _vertexesContainer.getVertexes(number))
				{
					printStream.println(VertexHelper.getVertexString(p));
				}
				printStream.close();
			}
			catch(FileNotFoundException e)
			{
				throw new RuntimeException(e);
			}
		}

		private void createVertexesContainer()
		{
			MapPropertySource properties = PolyhedronVertexFinder.getRecursiveAndAllCheckersProperties();
			properties.setValue(VertexesFinder.END_NUMBER, NUMBER);
			_vertexesContainer = new VertexesFinder(properties);
			_vertexesContainer.run();
		}

		private void processCheckResult(IVertexChecker checker, String check, int number)
		{
			if (checker instanceof PowVertexChecker || checker instanceof ProductVertexChecker)
			{
				return;
			}
			PrintStream stream = getFileOutputStream(checker, check, number);
			String formatted = check;
			if (checker instanceof SimplexMethodVertexChecker)
			{
				int index = check.indexOf("]") + 1;
				formatted = formatted.substring(index);
			}
			stream.println(formatted);
			stream.flush();
		}

		private PrintStream getFileOutputStream(IVertexChecker checker, String check, int number)
		{
			String fileName = FILENAME_PREFIX + number + "/" + checker.getClass().getSimpleName();
			if (checker instanceof SimplexMethodVertexChecker)
			{
				int index = check.indexOf("]");
				fileName += "_" + check.substring(1, index);
			}
			fileName += ".txt";
			if (!_name2Files.containsKey(fileName))
			{
				try
				{
					FileOutputStream stream = new FileOutputStream(fileName);
					BufferedOutputStream buffered = new BufferedOutputStream(stream);
					PrintStream printStream = new PrintStream(buffered);
					_name2Files.put(fileName, printStream);
				}
				catch(FileNotFoundException e)
				{
					throw new RuntimeException(e);
				}
			}
			return _name2Files.get(fileName);
		}
	}

}
